package com.sunday.minio.autoconfiguration;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import static com.sunday.minio.constants.MinioConstants.MINIO_PREFIX;

/**
 * MinIOAutoConfiguration
 * <p>
 * '@Configuration(proxyBeanMethods = false) 是一个 Spring 注解，用于标识一个类是配置类，并且可以在应用程序上下文中定义和注册 Bean。
 * 使用 @Configuration 注解的类通常包含了一些带有 @Bean 注解的方法，这些方法用于创建和配置各种 Bean 对象。这些 Bean 可以被其他组件或者应用程序的其他部分使用。
 * 其中，proxyBeanMethods 是 @Configuration 注解的一个属性，默认值为 true。当 proxyBeanMethods 设置为 true 时，Spring Framework 会通过 CGLIB（Code Generation Library）在运行时动态生成代理对象来管理 @Bean 方法的调用。这意味着每次调用带有 @Bean 注解的方法都会返回一个新的代理对象，允许 Spring 对 Bean 的依赖注入、AOP 等功能进行处理。
 * 但是，当 proxyBeanMethods 设置为 false 时，Spring Framework 不会生成额外的代理对象，而是直接调用带有 @Bean 注解的方法，并缓存其结果。这样做可以提高性能，但也可能导致某些 Spring 功能（如条件化 Bean 创建和 AOP）失效。
 * 因此，设置 proxyBeanMethods 为 false 可以提高应用程序的性能，但同时可能需要注意潜在的影响，特别是对于那些依赖 Spring AOP 或条件化 Bean 创建的场景。
 * '@ConditionalOnProperty 是 Spring Boot 中的一个注解，用于根据应用程序的配置属性条件来决定是否创建或加载某个 bean 或配置类。
 * 使用 @ConditionalOnProperty 注解时，你需要指定一个或多个属性键（key）作为条件，并提供这些属性键的预期值。当这些属性在应用程序的配置文件中存在且与预期值匹配时，相应的 bean 或配置类将被创建或加载。
 * 以下是 @ConditionalOnProperty 注解的使用示例：
 * java
 * '@Configuration
 * '@ConditionalOnProperty( value = "myapp.feature.enabled",
 * havingValue = "true",
 * matchIfMissing = true
 * )
 * public class MyFeatureConfiguration {
 * // 配置类的内容
 * }
 * 在上面的示例中，@ConditionalOnProperty 注解用于条件化地加载 MyFeatureConfiguration 配置类。它依赖于名为 myapp.feature.enabled 的属性，并且预期该属性的值为 true。如果该属性不存在，则通过 matchIfMissing = true 设置，默认情况下也会加载 MyFeatureConfiguration。
 * 你可以在应用程序的配置文件（如 application.properties 或 application.yml）中设置 myapp.feature.enabled 属性的值，以控制是否加载 MyFeatureConfiguration。
 * 请注意，在使用 @ConditionalOnProperty 注解时，你还可以提供其他属性，如 prefix、havingPrefix、name 等，以更灵活地指定属性的名称和前缀。
 * 总结起来，@ConditionalOnProperty 注解允许根据应用程序的配置属性条件来决定是否加载特定 bean 或配置类。
 * '@EnableConfigurationProperties(MinioConfigurationProperties.class) 是一个 Spring Boot 注解，用于启用对指定配置类的支持，并将其属性绑定到相应的 Bean 中。
 * 在这个特定的例子中，MinioConfigurationProperties 是一个配置类，它通常包含了与 MinIO 对象存储相关的配置属性，例如访问密钥、端点地址、桶（Bucket）名称等。通过使用 @EnableConfigurationProperties 注解，我们可以将这些配置属性绑定到 Spring 的环境中，并允许通过 @ConfigurationProperties 注解或 @Value 注解等方式进行访问和使用。
 * 在启用了 @EnableConfigurationProperties(MinioConfigurationProperties.class) 注解之后，在应用程序的其他地方，我们可以注入 MinioConfigurationProperties 类型的 Bean，以获得 MinIO 配置属性的值。这样，我们就能够轻松地访问和配置与 MinIO 相关的属性，以便在应用程序中使用 MinIO 对象存储服务。
 * 总结起来，@EnableConfigurationProperties(MinioConfigurationProperties.class) 注解的作用是启用对 MinioConfigurationProperties 配置类的支持，并将其中定义的属性绑定到相应的 Bean 中，以便在应用程序中方便地使用与 MinIO 相关的配置属性。
 * <p>
 * DefaultListableBeanFactory 是 Spring 框架中最重要的类之一。它是一个完全独立的 bean factory（Bean工厂），实现了 ListableBeanFactory 和 BeanDefinitionRegistry 接口。它是 Spring Ioc 容器默认的 BeanFactory 实现。
 * 该类主要负责管理和创建 bean。它在 Spring 容器中扮演了“Object 工厂”的角色，主要用于控制对象的创建、初始化、配置以及管理。
 * 以下是 DefaultListableBeanFactory 的一些主要职责：
 * 创建Bean实例：它会根据定义好的 BeanDefinition 来创建和返回 bean 实例。
 * 管理Bean：对于 singleton 类型的 bean，它会把它们放入一个用于缓存的容器中，以便在需要的时候去获取。
 * 处理Bean的依赖：它会尽可能早地处理循环依赖情况，解析并处理 bean 之间的依赖关系。
 * 支持Bean的生命周期：它能分辨出 bean 是否实现了特定的生命周期接口，例如 InitializingBean 或 DisposableBean，并在适当的时候调用相应的方法。
 * 简而言之，DefaultListableBeanFactory 是 Spring Ioc 容器核心实现，它负责创建和管理 bean，处理 bean 的依赖关系，并且支持 bean 的生命周期。
 *
 * @author zsy
 * @since 2023/10/13
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = MINIO_PREFIX, name = "enabled", matchIfMissing = true)
@EnableConfigurationProperties(MinioConfigurationProperties.class)
public class MinioAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public MinioDataSourceHandler minioDataSourceHandler(
            DefaultListableBeanFactory beanFactory,
            MinioConfigurationProperties minioProperties) {
        return new MinioDataSourceHandler(beanFactory, minioProperties);
    }

}
